package ctrlevent

import (
	eb "acs/eventbroker"
	"encoding/json"
	"errors"
	"fmt"

	log "github.com/Sirupsen/logrus"
)

// Listener 从eventbroker上监听事件, 并进行调度处理.
type Listener struct {
	eventChan interface{}
	// 上次处理过的事件号
	lastEventIndex  uint
	eventbrokerAddr []string
	eventCtrlKey    string
	watcher         *eb.Client
	brokerUser      string
	brokerPassword  string
}

// NewListener
// eventbrokerEndpoints e.g. ["http://127.0.0.1:2379", "http://127.0.0.1:2380"]. 默认为["http://127.0.0.1:2379"]
// key eventbroker中的文件,用于发布事件. e.g.  http://127.0.0.1:2379/v2/keys/acs/
// 当key为空时会panic
func NewListener(eventbrokerEndpoints []string, key string, brokerUser string, brokerPassword string) *Listener {
	if len(key) < 1 {
		panic("Empty event control point key")
	}
	if len(eventbrokerEndpoints) < 1 {
		eventbrokerEndpoints = []string{"http://127.0.0.1:2379"}
	}
	ls := &Listener{
		eventbrokerAddr: eventbrokerEndpoints,
		eventCtrlKey:    key,
		brokerUser:      brokerUser,
		brokerPassword:  brokerPassword,
	}
	return ls
}

// Serve 开始进行事件监听和调度处理
func (l *Listener) Listen(eventChan chan interface{}) error {
	var err error
	l.watcher, err = eb.NewClient(eb.Config{
		Endpoints: l.eventbrokerAddr,
		Username:  l.brokerUser,
		Password:  l.brokerPassword,
	})
	if err != nil {
		return err
	}
	var d interface{}
	msgChan := make(chan eb.WatchResponse)
	l.watcher.Watch(l.eventCtrlKey, msgChan, false)
	for {
		msg := <-msgChan
		err, d = l.decodeRawMsg(msg.Value)
		if err != nil {
			log.Warnf("Message decode error: %v", err)
		} else {
			eventChan <- d
		}
	}
}

func (l *Listener) decodeRawMsg(data string) (err error, t interface{}) {
	defer func() {
		fE := recover()
		if fE != nil {
			err = errors.New(fmt.Sprintf("%v", fE))
		}
	}()
	rawT := &EventRaw{}
	err = json.Unmarshal([]byte(data), rawT)
	if err != nil {
		return
	}

	switch rawT.Type {
	case EventPatchUpdate:
		ti := &PatchUpdate{}
		err = json.Unmarshal([]byte(rawT.Content), ti)
		if err != nil {
			return
		}
		return nil, *ti
	default:
		return errors.New(fmt.Sprintf("Unknown event type:[%v]", rawT.Type)), nil
	}
}
